home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Typography Samples / Circular Layout ƒ / Circular Layout.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  17.4 KB  |  520 lines  |  [TEXT/KAHL]

  1. /**\
  2. |**| =====================================================================
  3. |**|
  4. |**|    Circular Layout.c
  5. |**|
  6. |**|    This file contains the calls that this sample needs to make
  7. |**|    the QuickDraw GX shell work correctly.
  8. |**|
  9. |**|    QuickDraw GX Libraries Used:
  10. |**|    "color library.c", "font library.c", "graphics debug library.c",
  11. |**|    "layout library.c", "shape library.c", and "transform library.c".
  12. |**|
  13. |**|    ©1992-1994  Apple Computer, Inc.
  14. |**|    All rights reserved.
  15. |**|
  16. |**| =====================================================================
  17. \**/
  18.  
  19.  
  20. #include "QDGX shell.h"
  21. #include "layout routines.h"
  22. #include "layout library.h"
  23.  
  24.  
  25. /**\
  26. |**| ---------------------------------------------------------------------
  27. |**| PROTOTYPES
  28. |**| ---------------------------------------------------------------------
  29. \**/
  30.  
  31. // funtions required by shell
  32.  
  33. void    DoSetup            (void);
  34. void    DoDraw            (WindowPtr wind, Boolean updating);
  35. OSErr    DoCreateNew        (void);
  36. void    DoDispose        (WindowPtr wind);
  37. void    DoIdle            (WindowPtr wind);
  38. void    DoTeardown        (void);
  39. void    DoClick            (WindowPtr wind, Point p);
  40.  
  41. // private functions
  42.  
  43. OSErr    DoWindowInit        (WindowPtr wind);
  44. void    CreateSampleImage    (WindowPtr wind);
  45.  
  46.  
  47. /**\
  48. |**| ---------------------------------------------------------------------
  49. |**| ENUMS
  50. |**| ---------------------------------------------------------------------
  51. \**/
  52. enum { rWindResource = 128 };
  53.  
  54.  
  55. /**\
  56. |**| ---------------------------------------------------------------------
  57. |**| GLOBALS
  58. |**| ---------------------------------------------------------------------
  59. \**/
  60. // If gDebugging = TRUE, graphics library errors and notices will be posted.  This
  61. // functionality will only work with the "debugging" version of QuickDraw GX.
  62. // If the debugging version is not installed, nothing bad will happen, but these
  63. // functions will not work. 
  64.  
  65. Boolean        gDebugging = true;
  66.  
  67. // Set  "gGiveMeValidation" to TRUE if you want receive run-time validation.
  68.  
  69. Boolean        gGiveMeValidation = true;
  70.  
  71.  
  72. // gGraphicsHeapSize sets the size of the graphics heap created by calling the
  73. // GXNewGraphicsClient routine in main () within QuickDraw GX shell.c.  You can determine
  74. // the amount of graphics heap required by using GraphicsBug.  I'm giving it 600K,
  75. // since we need abunch if we have several windows open.
  76.  
  77. long        gGraphicsHeapSize = 600;
  78.  
  79. // gOurPrintingOverrideUPP is a universal proc pointer for our printing event
  80. // override.  This is so that our override can be native PowerPC code if necessary.
  81.  
  82. GXPrintingEventUPP    gOurPrintingOverrideUPP;
  83.  
  84.  
  85.  
  86. /**\
  87. |**| ---------------------------------------------------------------------
  88. |**| DoSetup()
  89. |**| Here's where we initialize any global variables our application needs.
  90. |**| We have only one at this time -- the universal proc pointer for
  91. |**| our printing override.
  92. |**| ---------------------------------------------------------------------
  93. \**/
  94. void DoSetup (void)
  95. {    // Initialize our printing event override UPP
  96.     gOurPrintingOverrideUPP = NewGXPrintingEventProc(MyPrintingEventOverride);
  97. }
  98.  
  99.  
  100. /**\
  101. |**| ---------------------------------------------------------------------
  102. |**| DoDraw()
  103. |**| Draw the contents of the window.  The first parameter is the window
  104. |**| to draw, and the second parameter is true if we're updating an existing
  105. |**| image.  If that's the case, we should redraw the ampersand shape and not
  106. |**| change the oval shape any.  If we do all our rotations and color 
  107. |**| adjustments on update events, when the system sets the clipping to only
  108. |**| the update region, the window gets terribly befuddled.  So, to counter
  109. |**| this, no changes are made to the shapes if we're updating, and we don't
  110. |**| erase the old shapes, but we _do_ draw the ampersand shape.
  111. |**| It sounds weird, but it works well.  Try it.
  112. |**| ---------------------------------------------------------------------
  113. \**/
  114. void DoDraw(WindowPtr wind, Boolean updating)
  115. {
  116.     gxShape            eraseOval;
  117.     gxShape            drawOval;
  118.     gxColor            drawOvalColor;
  119.     gxDashRecord    ourDash;
  120.     gxColor            gColorWhite = xRGB (0xFFFF, 0xFFFF, 0xFFFF);    
  121.     
  122. // First, initialize our document variables.
  123.  
  124.     drawOval = GetDocOvalShape(wind);
  125.     if (!updating)
  126.     {
  127.         (void *) GXGetShapeColor(drawOval, &drawOvalColor);
  128.         (void *) GXGetShapeDash(drawOval, &ourDash);
  129.  
  130. // Get the erasing oval from the document's structure. 
  131. // Drawing this "erase oval" on a white background wipes out the last drawing of
  132. // the drawOval shape.  We then cache it so we can draw it as fast as possible
  133. // later in this routine.
  134.  
  135.         eraseOval = GetDocEraseShape(wind);            // get the erasing shape
  136.         GXCopyToShape(eraseOval, drawOval);            // copy drawOval's geometry to eraseOval
  137.         GXSetShapeColor(eraseOval, &gColorWhite);     // set eraseOval's color to white
  138.         GXCacheShape(eraseOval);                    // make this draw faster below
  139.  
  140. // We now can erase the last-drawn oval when we please by drawing eraseOval.  Now,
  141. // we turn to drawing the next rotation of the drawOval.  First, we increment the
  142. // hue by 1/32 (in fixed notation) and increment the dash's phase by the same amount
  143. // (but this time in fract notation).
  144.  
  145.         drawOvalColor.element.hsv.hue += fixed1/32;
  146.         drawOvalColor.element.hsv.saturation += fixed1/24;
  147.         drawOvalColor.element.hsv.value += fixed1/20;
  148.         ourDash.phase += fract1/32;
  149.     
  150. // To make the changes to ourDash and drawOvalColor take effect, we have to stuff
  151. // them back in the shape.  Then we cache the drawOval shape so it will draw faster.
  152.  
  153.         GXSetShapeColor (drawOval, &drawOvalColor);
  154.         GXSetShapeDash (drawOval, &ourDash);
  155.         GXCacheShape (drawOval);
  156.         
  157. // Guess what?  GXGetShapeDash makes a copy of the dashing shape, so now we need
  158. // to dispose of it!  (This wasn't obvious to me, and took me some time to figure
  159. // out, so I'm boring you with this interesting tidbit in revenge.)
  160.  
  161.         GXDisposeShape(ourDash.dash);
  162.         
  163.     }
  164.  
  165. // Now we're ready to erase the old oval and draw the new one!  If we're updating,
  166. // draw the ampersand as well.
  167.  
  168.     if (!updating)
  169.         GXDrawShape(eraseOval);
  170.     GXDrawShape (drawOval);
  171.     
  172. }
  173.  
  174.  
  175. /**\
  176. |**| ---------------------------------------------------------------------
  177. |**| DoCreateNew()
  178. |**| This routine is called when a window needs to be created.
  179. |**| ---------------------------------------------------------------------
  180. \**/
  181. OSErr DoCreateNew (void)
  182. {
  183.     OSErr        err = noErr;
  184.     WindowPtr    wind;
  185.     
  186. // Get and create our window from the resource fork
  187.  
  188.     wind = GetNewWindow(rWindResource, nil, (WindowPtr)-1L);
  189.  
  190. // Attach a default gxViewPort to it, create and iInitialize our
  191. // private data for it, and add a sample image to its page shape.
  192.  
  193.     if ( wind == NULL )
  194.         return (MemError());
  195.  
  196.     GXIgnoreGraphicsNotice(transform_already_set);
  197.     SetDefaultViewPort(GXNewWindowViewPort(wind));            
  198.     GXPopGraphicsNotice();
  199.     
  200.     err = DoWindowInit(wind);
  201.     if ( err != noErr )
  202.         return err;
  203.     
  204.     CreateSampleImage(wind);
  205.     return err;
  206. }
  207.  
  208.  
  209. /**\
  210. |**| ---------------------------------------------------------------------
  211. |**| DoDispose()
  212. |**| This routine is called when a window needs to be disposed of.
  213. |**| ---------------------------------------------------------------------
  214. \**/
  215. void DoDispose (WindowPtr wind)
  216. {
  217.     TH_Doc    doc;
  218.     
  219. // You should always dispose of your GX graphics objects before tossing your window.
  220. // Why?  It's generally good form and this approach guarantees that everything is
  221. // disposed.  If you had not disposed of everything, the call to DisposeWindow should
  222. // dispose of the objects. If you are running the debugging version of QuickDraw GX
  223. // with notices set, you will receive a notice that you had not disposed of everything.
  224. // You can turn notices on in this file by setting gDebugging = TRUE (above).
  225.     
  226.     if ( wind != NULL )
  227.     {
  228.         doc = (TH_Doc)GetWRefCon(wind);        // Remember, this is where we stored our private data.
  229.         GXDisposeShape(GetDocOvalShape(wind));     // Dispose of this doc's oval.
  230.         GXDisposeShape(GetDocEraseShape(wind));    // Dispose of this doc's erasing shape
  231.         GXDisposeJob(GetDocJob(wind));        // Dispose of this doc's print job.
  232.         DisposHandle((Handle) doc);            // Dispose of our private data.
  233.         DisposeWindow(wind);                // Dispose of the window.
  234.     }
  235. }
  236.  
  237.  
  238. /**\
  239. |**| ---------------------------------------------------------------------
  240. |**| DoIdle()
  241. |**| This routine is called to do things while idling through the event loop.
  242. |**| ---------------------------------------------------------------------
  243. \**/
  244. void DoIdle (WindowPtr wind)
  245. {
  246.     if ( wind != NULL )
  247.         if ((((WindowPeek)wind)->windowKind == userKind) && (wind != nil))
  248.             DoDraw(wind, false);
  249. }
  250.  
  251. /**\
  252. |**| ---------------------------------------------------------------------
  253. |**| DoTeardown()
  254. |**| This routine is called just before we quit to remove anything 
  255. |**| persistent that might have been setup by DoSetup().
  256. |**| ---------------------------------------------------------------------
  257. \**/
  258. void DoTeardown (void)
  259. {
  260.     DisposeRoutineDescriptor(gOurPrintingOverrideUPP);
  261. }
  262.  
  263.  
  264. /**\
  265. |**| ---------------------------------------------------------------------
  266. |**| DoClick()
  267. |**| ---------------------------------------------------------------------
  268. \**/
  269. void DoClick(WindowPtr window, Point p)
  270. {
  271. }
  272.  
  273.  
  274.  
  275.  
  276.  
  277. /**\
  278. |**| ---------------------------------------------------------------------
  279. |**| DoWindowInit()
  280. |**| In this function we create and initialize the the private document
  281. |**| structure for a new window.  This structure contains the print job and
  282. |**| the shape which is drawn in the window.  We store this data in a handle
  283. |**| and hang it off the window's refCon field for easy retrieval.  By doing
  284. |**| this, rather than using globals, we can create many windows containing
  285. |**| unique print jobs and shapes.
  286. |**| ---------------------------------------------------------------------
  287. \**/
  288. OSErr DoWindowInit (WindowPtr wind)
  289. {
  290.     OSErr    err = noErr;
  291.     gxJob    docJob;
  292.     TH_Doc    windDoc;
  293.  
  294.  
  295. // Create a print job for this document.  This will be the same as the system default until
  296. // the user goes through the dialogs for Page Setup or Print…
  297.  
  298.     err = GXNewJob(&docJob);
  299.     
  300.     
  301. // If there are no errors, create a handle the size of our document structure and store
  302. // the print job in it.  Store the handle in the window's refCon field so that we can
  303. // get at it.  (Note that the utility routine "GetDocJob" can be used to do this easily.
  304.  
  305.     if ( err == noErr )
  306.     {
  307.         windDoc = (TH_Doc) NewHandleClear(sizeof(T_Doc));
  308.  
  309.         if ( windDoc == NULL )
  310.             err = MemError();
  311.         else
  312.         {
  313.             (*windDoc)->docJob = docJob;
  314.             SetWRefCon(wind, (long) windDoc);
  315.         }
  316.  
  317. // Now install our application override for PrintingEvent so that we can
  318. // support the new movable-modal printing dialog boxes.
  319.  
  320.         GXInstallApplicationOverride(docJob, gxPrintingEvent, gOurPrintingOverrideUPP);
  321.  
  322.     }
  323.  
  324.     return err;
  325. }
  326.  
  327.  
  328. /**\
  329. |**| ---------------------------------------------------------------------
  330. |**| CreateSampleImage()
  331. |**| This function creates primitive shapes and adds them to the window's page shape.
  332. |**| ---------------------------------------------------------------------
  333. \**/
  334. void CreateSampleImage (WindowPtr wind)
  335. {
  336.     Rect    ourWindowRect = wind->portRect; // the rectangle for this window
  337.                                             // in QuickDraw coordinates
  338.     gxShape         layout;                        // the layout shape we dash the oval with
  339.     gxShape         oval;                        // the oval that the layout lives in
  340.     gxShape            eraseOval;                    // another oval shape to erase with
  341.     gxDashRecord     ourDash;                    // the record for our complex dash
  342.     gxColor         ovalColor;                    // the color for the oval
  343.     gxRectangle     bounds;                        // the bounds of various shapes (reused)
  344.     gxRectangle        ourRectangle;                // the rectangle for the oval's use
  345.     gxRunControls     runControls;                // default run controls for layouts
  346.     gxLayoutOptions layoutOptions;                // default layout options for layouts
  347.     char             *textRuns[3];                // array of text runs for our dash layout
  348.     gxStyle         textStyles[3];                // array of styles for our dash layout
  349.     short             textLengths[3];                // array of lengths for our dash layout
  350.     short            totalLength;                // total length of the text
  351.     short            level0 = 0;                    // variable for use with GXNewLayout
  352.     char *            text1  = "Aetna ";            // text run #1
  353.  
  354. //  Text run #2 is "Arabic Macintosh" in Arabic: 
  355. //  meem, alif, kaf,  noon, tah,  wau,  shin, <sp>, alif, lam,  ein,  reh,  beh,  yeh 
  356.  
  357.     static char     text2[] =  {0xE5, 0xC7, 0xE3, 0xE6, 0xCA, 0xE8, 0xD4,
  358.                                 0x20, 0xC7, 0xE4, 0xD9, 0xD1, 0xC8, 0xEA, 0};
  359.                                 
  360.     char *            text3  = " Office AWAY.";    // text run #3
  361.     gxPoint         center;                        // center of all the graphics we do
  362.     
  363.  
  364. // Find the center of the window in fixed coordinates
  365.  
  366.     center.x = ff((ourWindowRect.right - ourWindowRect.left) / 2);
  367.     center.y = ff((ourWindowRect.bottom - ourWindowRect.top) / 2);
  368.         
  369. // Make a 270 x 270 gxRectangle centered in the window 
  370.  
  371.     ourRectangle.top = center.y - ff(135);
  372.     ourRectangle.left = center.x - ff(135);
  373.     ourRectangle.bottom = center.y + ff(135);
  374.     ourRectangle.right = center.x + ff(135);
  375.     
  376. // Use ourRectangle to make an oval, and get it ready to be dashed.
  377.  
  378.     oval = NewOval(&ourRectangle);
  379.     GXSetShapeFill(oval, gxClosedFrameFill);
  380.     GXSetShapePen(oval, IntToFixed(14));
  381.     (void *) SetCommonColor(&ovalColor, red);
  382.     (void *) GXConvertColor(&ovalColor, gxHSVSpace, nil, nil);    // convert to HSV
  383.     
  384. // Copy the same oval to our eraseOval shape so we can use it later.
  385.  
  386.     eraseOval = GXNewShape(gxPathType);
  387.     GXCopyToShape(eraseOval, oval);
  388.  
  389. // Initialize the array of text runs for our layout shape
  390.  
  391.     textRuns[0] = text1;
  392.     textRuns[1] = text2;
  393.     textRuns[2] = text3;
  394.     
  395. // Initialize the text lengths.  MyStrLength is a function in this file.
  396.  
  397.     textLengths[0] = MyStrLength(text1);
  398.     textLengths[1] = MyStrLength(text2);
  399.     textLengths[2] = MyStrLength(text3);
  400.     
  401.     totalLength = textLengths[0] + textLengths[1] + textLengths[2];
  402.  
  403. // Use library routines to initialize default gxLayoutOptions and gxRunControls structures
  404.  
  405.     InitializeLayoutOptions (&layoutOptions);
  406.     InitializeRunControls (&runControls);
  407.     
  408. // Use the library routines to initialize three style runs.  The first one is 28-point
  409. // Helvetica.  NewLayoutStyle is found in layout library.c.
  410.  
  411.     textStyles[0] = NewLayoutStyle(
  412.         (char *) "\pHoefler Text",            // the gxFontName for the style
  413.         ff(28),                            // the point size in fixed point
  414.         0,                                // gxTextAttributes (none)
  415.         &runControls,                    // our default run controls
  416.         nil,                            // run features (none for us)
  417.         0,                                // count of run features
  418.         nil);                            // style run overrides (none for us)
  419.  
  420. // The second one is 28-point Baghdad.
  421.  
  422.     textStyles[1] = NewLayoutStyle(
  423.         (char *) "\pBaghdad Plain",        // the gxFontName for the style
  424.         ff(28),                            // the point size in fixed format
  425.         0,                                // gxTextAttributes (none)
  426.         &runControls,                    // our default run controls
  427.         nil,                            // run featuers (none for this style)
  428.         0,                                 // count of run features
  429.         nil);                            // style run overrides (none for us)
  430.     
  431. // The third and final one is 28-point Times Roman
  432.  
  433.     textStyles[2] = NewLayoutStyle(
  434.         (char *) "\pHoefler Text Italic",// the gxFontName for this style
  435.         ff(28),                            // the point size (fixed format)
  436.         0,                                // no gxTextAttributes
  437.         &runControls,                    // our default run controls
  438.         nil,                            // no run features
  439.         0,                                // count of no run features = 0
  440.         nil);                            // style run overrides (still none)
  441.     
  442. // We're ready to build our layout now!
  443.  
  444.     layout = GXNewLayout(
  445.         3,                                    // count of text runs
  446.         textLengths,                        // array of lengths of each run
  447.         (void *)textRuns,                    // array of pointers to the text
  448.         3,                                    // count of style runs
  449.         textLengths,                        // array of the byte lengths of each run
  450.         textStyles,                            // array of the styles
  451.         1,                                    // number of levels in the layout
  452.         &totalLength,                        // array of lengths of levels (only one)
  453.         &level0,                            // array of the levels (only one)
  454.         &layoutOptions,                        // options (default)
  455.         nil);                                // position of the layout shape (none)
  456.         
  457.     GXSetShapeColor(layout, &ovalColor);
  458.         
  459. // Now we get the bounds of the layout shape to determine how to proceed with the dashing.
  460. // Why are we using GXGetShapeBounds instead of GXGetShapeTypographicBounds?  The latter
  461. // does not include the size of any hanging punctuation in the width; the former does.
  462. // Since we're only interested in the width this time, that's the call we want.
  463.  
  464.     (void) GXGetShapeBounds (layout, 0, &bounds);
  465.     
  466. // Changing the shape to a path type will make dashing it faster.  We could also call
  467. // GXPrimitiveShape twice to do this (the first time makes a glyph shape).
  468.  
  469.     GXSetShapeType(layout, gxPathType);
  470.     
  471. // We're ready to use the layout/path shape as the dash shape for our oval.
  472. // Initialize our dash record and use it!
  473.  
  474.     ourDash.attributes = 
  475.         gxAutoAdvanceDash | gxBreakDash;        // use whole multiples of dash shapes
  476.     ourDash.dash = layout;                        // the shape to dash with
  477.     ourDash.phase = 0;                            // the initial phase
  478.     ourDash.advance = bounds.right + ff(10);    // the advance (shape size + 10 pixels)
  479.     ourDash.scale = IntToFixed(14);                // the scale perpendicular to contour
  480.  
  481.     GXSetShapeDash (oval, &ourDash);
  482.  
  483. // Now scale the oval shape to fill the window.
  484.     
  485.     GXScaleShape(
  486.         oval,                                // the shape to get the transform from
  487.         (fixed)0x00016000,                    // scale it horizontally by 1 3/8
  488.         (fixed)0x00016000,                    // and vertically by 1 3/8
  489.         center.x,                            // about the center of the rectangle
  490.         center.y);                            // as previously determined
  491.     
  492.  
  493. // Save the layout and ampersand shapes for this window in the doc structure
  494. // attached to this document.
  495.     
  496.     {
  497.     
  498.         TH_Doc    windDoc;                    // the document structure
  499.         
  500.         windDoc = (TH_Doc) GetWRefCon(wind);
  501.         (*windDoc)->docOval = oval;
  502.         (*windDoc)->eraseOval = eraseOval;
  503.         
  504.     }
  505.         
  506.         
  507. // Dispose of all things we allocated in here that we don't need to keep.
  508.  
  509.     GXDisposeShape(layout);
  510.     GXDisposeStyle (textStyles[0]);
  511.     GXDisposeStyle (textStyles[1]);
  512.     GXDisposeStyle (textStyles[2]);
  513.  
  514.  
  515. // Invalidate the window's portRect so that everything gets updated.
  516.     
  517.     SetPort(wind);
  518.     InvalRect(&ourWindowRect);
  519. }
  520.